#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#define close free

char* ts;
int nls;//split()函数分配指针数组的个数记录 
char** ls;//split()函数分隔后的多个字符串形成的list列表

typedef struct String
{
	char* shead;
	int length;
	
	struct String* (*newString)(void);
	int (*len)(struct String* p);
	char* (*lower)(struct String* p);
	void (*tolower)(struct String* p);
	char* (*upper)(struct String* p);
	void (*toupper)(struct String* p);
	bool (*islower)(struct String* p);
	bool (*isupper)(struct String* p);
	bool (*isprintable)(struct String* p);
	char* (*slice)(struct String* p,int start,int end,int step);
	bool (*isnumeric)(struct String* p);
	bool (*isspace)(struct String* p);
	char** (*split)(struct String* p,char sep,int maxsplit);
}String;

int len(String* p);
char* lower(String* p);
char* upper(String* p);
bool islower(String* p);
void tolower(String* p);
bool isupper(String* p);
void toupper(String* p);
bool isprintable(String* p);
char* slice(String* p,int start,int end,int step);
bool isnumeric(String* p);
bool isspace(String* p);
char** split(String* p,char sep,int maxsplit);

String* newString(void)
{ 	
	String* sp;
	sp = (String*)malloc(sizeof(String));
	sp->shead = (char*)malloc(sizeof(char)*100+1);
	(sp->shead)[0] = '\0';
	sp->length = 0;
	
	ts = (char*)malloc(sizeof(char)+1);
	ts[0] = '\0';
	
	sp->newString = newString;
	sp->len = len;
	sp->lower = lower;
	sp->upper = upper;	
	sp->islower = islower;
	sp->tolower = tolower;
	sp->isupper = isupper;
	sp->toupper = toupper;
	sp->isprintable = isprintable;
	sp->slice = slice;
	sp->isnumeric = isnumeric;
	sp->isspace = isspace;
	sp->split = split;
	return sp;
}//初始化分配一个101字节的字符数组

int len(String* p)
{
	return p->length = strlen(p->shead);
}
char* lower(String* p)
{
	int i;
	close(ts);
	ts = (char*)malloc(sizeof(char)*len(p)+1);
	ts[0] = '\0';
	for(i = 0;i < len(p);i++)
	{
		if((p->shead)[i] >= 'A' && (p->shead)[i] <= 'Z')
		{
			ts[i] = (p->shead)[i] + 32;
			//printf("%c\n",ts[i]);
		}
		else
		{
			ts[i] = (p->shead)[i];
		}
	}
	ts[len(p)] = '\0';
	return ts;
}
void tolower(String* p)
{
	int i;
	for(i = 0;i < len(p);i++)
	{
		if((p->shead)[i] >= 'A' && (p->shead)[i] <= 'Z')
		{
			(p->shead)[i] = (p->shead)[i] + 32;
			//printf("%c\n",ts[i]);
		}
	}

	return;
}
char* upper(String* p)
{
	int i;
	close(ts);
	ts = (char*)malloc(sizeof(char)*len(p)+1);
	ts[0] = '\0';
	for(i = 0;i < len(p);i++)
	{
		if((p->shead)[i] >= 'a' && (p->shead)[i] <= 'z')
		{
			ts[i] = (p->shead)[i] - 32;
			//printf("%c\n",ts[i]);
		}
		else
		{
			ts[i] = (p->shead)[i];
		}
	}
	ts[len(p)] = '\0';
	return ts;
}
void toupper(String* p)
{
	int i;
	for(i = 0;i < len(p);i++)
	{
		if((p->shead)[i] >= 'a' && (p->shead)[i] <= 'z')
		{
			(p->shead)[i] = (p->shead)[i] - 32;
			//printf("%c\n",ts[i]);
		}
	}

	return;
}
bool islower(String* p)
{
	int i;
	bool existEn = false;
	for(i = 0;i < len(p);i++)
	{
		if((p->shead)[i] >= 'A' && (p->shead)[i] <= 'Z') 
		{
			existEn = true;
			break;
		}
		if((p->shead)[i] >= 'a' && (p->shead)[i] <= 'z') 
		{
			existEn = true;
			break;
		}
	}//检查是否存在英文字母 
	if(existEn == false)
	{
		return false;
	}
	else
	{
		for(i = 0;i < len(p);i++)
		{
			if((p->shead)[i] >= 'A' && (p->shead)[i] <= 'Z') 
			{
				return false;
			}
		}	
	}
	return true;
}
bool isupper(String* p)
{
	int i;
	bool existEn = false;
	for(i = 0;i < len(p);i++)
	{
		if((p->shead)[i] >= 'A' && (p->shead)[i] <= 'Z') 
		{
			existEn = true;
			break;
		}
		if((p->shead)[i] >= 'a' && (p->shead)[i] <= 'z') 
		{
			existEn = true;
			break;
		}
	}//检查是否存在英文字母 
	if(existEn == false)
	{
		return false;
	}
	else
	{
		for(i = 0;i < len(p);i++)
		{
			if((p->shead)[i] >= 'a' && (p->shead)[i] <= 'z') 
			{
				return false;
			}
		}	
	}
	return true;
}
bool isprintable(String* p)
{
	int i;
	for(i = 0;i < len(p);i++)
	{
		if((p->shead)[i] <= 31 && (p->shead)[i] >= 0) 
		{
			printf("不可打印字符ASCII值：%d\n",(p->shead)[i]);
			return false;
		}
		if((p->shead)[i] == 127)
		{
			return false;
		}
	}
	return true;	
}
bool isnumeric(String* p)
{
	int i;
	bool existEn = false;
	for(i = 0;i < len(p);i++)
	{
		if((p->shead)[i] >= '0' && (p->shead)[i] <= '9') 
		{
			existEn = true;
			break;
		}
	}//检查是否存在数字 
	if(existEn == false)
	{
		return false;
	}
	else
	{
		for(i = 0;i < len(p);i++)
		{
			if((p->shead)[i] < 48 || (p->shead)[i] > 57) 
			{
				return false;
			}
		}
	}
	return true;	
}
bool isspace(String* p)
{
	int i;
	for(i = 0;i < len(p);i++)
	{
		if((p->shead)[i] != ' ') 
		{
			return false;
		}
	}
	return true;	
}

char* slice(String* p,int start,int end,int step)
{
	int i;
	int t = 0;
	
	close(ts);
	ts = (char*)malloc(sizeof(char)*len(p)+1);
	ts[0] = '\0';
	
	if(start >= 0 && end <= len(p) && start <= end && step >= 0)
	{
		for(i = start;i < end;i = i + step,t++)
		{
			ts[t] = (p->shead)[i];
		}
		ts[t] = '\0';
	}//正向增前进
	else if(start <= len(p) && end >= 0 && start >= end && step < 0)
	{
		for(i = start;i > end;i = i + step,t++)
		{
			ts[t] = (p->shead)[i];
		}		
		ts[t] = '\0';
	}//负向倒退
	else
	{
		ts[0] = '\0';
	}
	return ts;		
}
char** split(String* p,char sep,int maxsplit)
{
	int i;
	int sepcount = 0;
	int index[len(p)];
	int dtt = 0;
	int tdt = 0;
	int dxx = 0,dyy = 0;
	for(i = 0;i < len(p);i++)
	{
		index[i] = -1;//index数组全赋初始值1 
	}
	for(i = 0;i < len(p);i++)
	{
		if((p->shead)[i] == sep)
		{
			index[dtt] = i;//按照顺序检查到分隔符sep就把其在字符串中的位置记录在index数组中（从index数组0位置记录） 
			//printf("\n已记录分隔符位置%d在index[%d]中\n",i,dtt); 
			//printf("dt:%d",dtt);
			dtt++; 
			sepcount++;
		}
	}//检查字符串中有几个分隔符，为后续的分配空间提供参数 
	
	if(maxsplit < 0)
	{
		//printf("\n找到了sepcount:%d个分隔符\n",sepcount);
		//char** ls;
		ls = (char**)malloc(sizeof(char*)*(sepcount+1));//按照字符串被划分的段数，分配相应数目的字符指针数组的个数，每个指针指向一段malloc分配的空间，存放分隔后的字符串

		nls = sepcount+1;
		for(i = 0;i < sepcount+1;i++)
		{
			if(i == 0)
			{
				ls[i] = (char*)malloc(sizeof(char)*(index[i]-0)+1);	
				//printf("\nls[%d]:分配了%d字节！\n",i,index[i]-0+1);
				ls[i][0] = '\0';				
			}
			else if(i == sepcount)
			{
				ls[i] = (char*)malloc(sizeof(char)*(len(p)-index[dtt-1]));
				//printf("\nls[%d]:分配了%d字节！\n",i,len(p)-index[dtt-1]);
				ls[i][0] = '\0';	
			}
			else
			{
				ls[i] = (char*)malloc(sizeof(char)*(index[i]-index[i-1])+1);
				//printf("\nls[%d]:分配了%d字节！\n",i,index[i]-index[i-1]);
				ls[i][0] = '\0';	
			}	
		}//已经给每段字符串精准分配好空间，下面开始实际分隔操作
		for(i = 0;i < len(p);i++)
		{
			if(i != index[tdt])
			{
				ls[dxx][dyy++] = (p->shead)[i];
				//printf("赋值：%c",(p->shead)[i]);
			}
			else
			{
				ls[dxx][dyy] = '\0';
				//puts("分隔检查：");
				//printf("i:%d,",i); 
				//puts(ls[dxx]);
				tdt++;
				dxx++;
				dyy = 0;
			}
		}
		ls[dxx][dyy] = '\0';
		//puts("分隔检查：");
		//printf("i:%d,",i); 
		//puts(ls[dxx]);
		//printf("\n%d\n",sizeof(ls)/sizeof(char*));
		return ls;
	} 
	else
	{
		return NULL;
		//不再实现，可由上述情况的实现改编而来 		
	}
} 
void putls(char** ls)
{
	int i;	
	printf("[");
	for(i = 0;i < nls;i++)
	{
		if(i == nls-1)
		{
			printf("\'""%s""\'",ls[i]);
		}
		else
		{
			printf("\'""%s""\',",ls[i]);
		}	
	}
	printf("]");
	return;
}
void finalString()
{
	close(ts);
}
void finalsplit()
{
	int i;
	for(i = 0;i < nls;i++)
	{
		close(ls[i]);
	}
	close(ls);
} 
int main()
{
	String* s = newString();
	int f,e,stp;
	char ssp;
	
	puts("请输入一个字符串：");
	gets(s->shead);
	printf("\n输入分隔符：");
	fflush(stdin);
	scanf("%c",&ssp); 
	printf("分割后list:");
	putls(s->split(s,ssp,-1));
	puts("");
	printf("\n检查该字符串是否全是空格：%s\n",s->isspace(s)?"true":"false");
	printf("检查该字符串是否全是数字：%s\n",s->isnumeric(s)?"true":"false");
	
	printf("\n输入切片起止范围与步长（空格分隔）：");
	scanf("%d %d %d",&f,&e,&stp); 
	
	String* s_slice= newString();
	s_slice->shead = s->slice(s,f,e,stp);
	puts(s_slice->shead);
	
	printf("\n将该切片分割，输入分隔符：");
	fflush(stdin);
	scanf("%c",&ssp); 
	printf("分割后list:");
	putls(s->split(s_slice,ssp,-1));
	puts("");
	
	printf("检查该字符串是否全是可打印字符：%s\n",s->isprintable(s)?"true":"false");
	printf("该字符串英文字母是否全小写：%s\n",s->islower(s)?"true":"false");
	printf("该字符串英文字母是否全大写：%s\n",s->isupper(s)?"true":"false");
	
	puts("输出该字符串英文字母全小写和全大写的副本（不改变源字符串）：");
	puts(s->lower(s));
	puts(s->upper(s));
	
	puts("【执行】--将源字符串【英文字母】全变成【小写】！"); 
	s->tolower(s);
	printf("该字符串英文字母是否全小写：%s\n",s->islower(s)?"true":"false");
	printf("该字符串英文字母是否全大写：%s\n",s->isupper(s)?"true":"false");
	
	puts("【执行】--将源字符串【英文字母】全变成【大写】！"); 
	s->toupper(s);
	printf("该字符串英文字母是否全小写：%s\n",s->islower(s)?"true":"false");
	printf("该字符串英文字母是否全大写：%s\n",s->isupper(s)?"true":"false");
	
	printf("字符串长度:%d\n",s->len(s));

	finalString();//只要调用了lower或upper才可以使用 
	finalsplit();//只要调用了split才可以使用 
	return 0;
}